package com.huawei.util;

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

import java.io.FileInputStream;
import java.io.IOException;
import java.time.ZoneId;
import java.util.*;

/**
 * 使用 Apache POI 读取 Excel，返回 List<Map<String, Object>>
 * - 第一行作为表头（Header）
 * - 后续行作为数据，每行转为 Map<表头, 单元格值>
 * - 支持 .xls 和 .xlsx
 * - 支持指定 sheet（索引或名称）
 */
public class ApachePOIExcelMapReader {

    // ==================== 核心方法：返回 List<Map<String, Object>> ====================

    /**
     * 读取指定索引的 sheet，返回 List<Map<String, Object>>
     *
     * @param filePath   Excel 文件路径
     * @param sheetIndex 工作表索引（从 0 开始）
     * @return 每行是一个 Map，key 为表头，value 为单元格值（Object 类型）
     * @throws IOException 文件读取异常
     */
    public static List<Map<String, Object>> readToMapList(String filePath, int sheetIndex) throws IOException {
        try (FileInputStream fis = new FileInputStream(filePath);
             Workbook workbook = getWorkbook(fis, filePath)) {

            if (sheetIndex < 0 || sheetIndex >= workbook.getNumberOfSheets()) {
                throw new IllegalArgumentException("无效的 sheet 索引: " + sheetIndex +
                        "，有效范围: 0 ~ " + (workbook.getNumberOfSheets() - 1));
            }

            Sheet sheet = workbook.getSheetAt(sheetIndex);
            return readSheetToMapList(sheet);
        }
    }

    /**
     * 读取指定名称的 sheet，返回 List<Map<String, Object>>
     *
     * @param filePath  Excel 文件路径
     * @param sheetName 工作表名称
     * @return List<Map<String, Object>>
     * @throws IOException 文件读取异常
     */
    public static List<Map<String, Object>> readToMapList(String filePath, String sheetName) throws IOException {
        try (FileInputStream fis = new FileInputStream(filePath);
             Workbook workbook = getWorkbook(fis, filePath)) {

            Sheet sheet = workbook.getSheet(sheetName);
            if (sheet == null) {
                throw new IllegalArgumentException("未找到名为 '" + sheetName + "' 的工作表。可用的工作表: " +
                        getAvailableSheetNames(workbook));
            }

            return readSheetToMapList(sheet);
        }
    }

    /**
     * 读取第一个 sheet（索引 0），返回 List<Map<String, Object>>
     */
    public static List<Map<String, Object>> readToMapList(String filePath) throws IOException {
        return readToMapList(filePath, 0);
    }

    // ==================== 内部实现 ====================

    /**
     * 将 Sheet 转换为 List<Map<String, Object>>
     * - 第一行：表头（Header）
     * - 第二行起：数据行
     */
    private static List<Map<String, Object>> readSheetToMapList(Sheet sheet) {
        List<Map<String, Object>> result = new ArrayList<>();

        // 获取总行数
        int totalRows = sheet.getPhysicalNumberOfRows();
        if (totalRows == 0) {
            return result; // 空表
        }

        // 读取表头（第一行）
        Row headerRow = sheet.getRow(0);
        if (headerRow == null) {
            throw new IllegalStateException("Excel 第一行（表头）为空，请确保第一行包含列名");
        }

        // 提取表头：按列索引 -> 表头字符串
        List<String> headers = new ArrayList<>();
        int lastCellNum = headerRow.getLastCellNum(); // 物理最大列（可能包含空列）
        if (lastCellNum <= 0) {
            throw new IllegalStateException("表头行没有有效列");
        }

        for (int i = 0; i < lastCellNum; i++) {
            Cell cell = headerRow.getCell(i, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
            String header = getCellStringValue(cell);
            // 如果表头为空，用 "Column_N" 代替（避免 key 重复或 null）
            if (header == null || header.trim().isEmpty()) {
                header = "Column_" + i;
            }
            headers.add(header.trim());
        }

        // 读取数据行（从第 1 行开始，即第二行）
        for (int rowIndex = 1; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
            Row row = sheet.getRow(rowIndex);
            Map<String, Object> rowMap = new LinkedHashMap<>(); // 保持列顺序

            if (row == null) {
                // 空行：创建空 Map（或跳过，这里选择保留空行）
                for (String header : headers) {
                    rowMap.put(header, null);
                }
                result.add(rowMap);
                continue;
            }

            // 按表头列数填充数据
            for (int colIndex = 0; colIndex < headers.size(); colIndex++) {
                String header = headers.get(colIndex);
                Cell cell = row.getCell(colIndex, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
                Object value = getCellValue(cell); // 保留原始类型
                rowMap.put(header, value);
            }

            result.add(rowMap);
        }

        return result;
    }

    // ==================== 工具方法 ====================

    /**
     * 获取单元格的字符串表示（仅用于表头）
     */
    private static String getCellStringValue(Cell cell) {
        if (cell == null || cell.getCellType() == CellType.BLANK) {
            return null;
        }
        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return cell.getDateCellValue().toString();
                } else {
                    double val = cell.getNumericCellValue();
                    if (val == Math.floor(val)) {
                        return String.valueOf((long) val);
                    } else {
                        return String.valueOf(val);
                    }
                }
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                try {
                    return cell.getStringCellValue();
                } catch (Exception e) {
                    return String.valueOf(cell.getNumericCellValue());
                }
            default:
                return null;
        }
    }

    /**
     * 获取单元格的原始 Java 对象值（用于数据行）
     */
    private static Object getCellValue(Cell cell) {
        if (cell == null || cell.getCellType() == CellType.BLANK) {
            return null;
        }

        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    Date date = cell.getDateCellValue();
                    return date.toInstant()
                            .atZone(ZoneId.systemDefault())
                            .toLocalDateTime();
                } else {
                    return cell.getNumericCellValue(); // Double
                }
            case BOOLEAN:
                return cell.getBooleanCellValue();
            case FORMULA:
                try {
                    switch (cell.getCachedFormulaResultType()) {
                        case STRING:
                            return cell.getStringCellValue();
                        case NUMERIC:
                            if (DateUtil.isCellDateFormatted(cell)) {
                                Date date = cell.getDateCellValue();
                                return date.toInstant()
                                        .atZone(ZoneId.systemDefault())
                                        .toLocalDateTime();
                            } else {
                                return cell.getNumericCellValue();
                            }
                        case BOOLEAN:
                            return cell.getBooleanCellValue();
                        default:
                            return null;
                    }
                } catch (Exception e) {
                    return null;
                }
            case ERROR:
            default:
                return null;
        }
    }

    /**
     * 根据文件扩展名创建 Workbook
     */
    private static Workbook getWorkbook(FileInputStream fis, String filePath) throws IOException {
        if (filePath.toLowerCase().endsWith(".xlsx")) {
            return new XSSFWorkbook(fis);
        } else if (filePath.toLowerCase().endsWith(".xls")) {
            return new HSSFWorkbook(fis);
        } else {
            throw new IllegalArgumentException("不支持的文件格式: " + filePath + "（仅支持 .xls 和 .xlsx）");
        }
    }

    /**
     * 获取所有 sheet 名称（用于错误提示）
     */
    private static String getAvailableSheetNames(Workbook workbook) {
        List<String> names = new ArrayList<>();
        for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
            names.add(workbook.getSheetName(i));
        }
        return String.join(", ", names);
    }
}
